package com.api.controller;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateUtil;
import com.common.annotation.PassToken;
import com.common.apiResult.ApiController;
import com.common.apiResult.ApiResult;
import com.framework.service.TokenService;
import com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse;
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
import com.github.binarywang.wxpay.bean.request.BaseWxPayRequest;
import com.github.binarywang.wxpay.bean.request.WxPayRefundRequest;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
import com.github.binarywang.wxpay.bean.result.BaseWxPayResult;
import com.github.binarywang.wxpay.bean.result.WxPayRefundResult;
import com.github.binarywang.wxpay.constant.WxPayConstants;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.util.Date;

/**
 * @ClassName WxPayController
 * @Description 微信支付
 * @Date 2020/10/11 10:49
 * Create By Renbowen
 * TODO 小程序支付需要申请开通jsApi支付
 */
@RestController
@RequestMapping(value = "/api/weChatPay")
@Slf4j
public class WxPayController extends ApiController {

    /**
     * 微信支付回调地址
     */
    @Value("${wx.notifyUrl}")
    private String notifyUrl;

    /**
     * 微信app支付appId
     */
    @Value("${wechat.app.appId}")
    private String weChatPayAppId;

    /**
     * WxJava封装的微信支付
     */
    private final WxPayService wxPayService;

    /**
     * jwt Token服务
     */
    private final TokenService tokenService;

    /**
     * wxJava小程序操作API
     */
    private final WxMaService wxMaService;

    public WxPayController(WxPayService wxPayService, TokenService tokenService, WxMaService wxMaService) {
        this.wxPayService = wxPayService;
        this.tokenService = tokenService;
        this.wxMaService = wxMaService;
    }

    /**
     * 微信小程序拉起支付
     *
     * @return
     * @throws WxPayException
     */
    @RequestMapping(value = "/toPayByMiniProgram", method = RequestMethod.POST)
    @Transactional(rollbackFor = Exception.class)
    @PassToken
    public ApiResult toPayByMiniProgram(String code, HttpServletRequest request) throws WxPayException, WxErrorException {
//        String primaryId = map.get("goodsId");
//        log.info("参数的productId：{{}}", primaryId);
//        if (StringUtils.isAnyBlank(primaryId)) {
//            return ApiResult.fail("参数不能为null");
//        }
//        Long goodsId = CONVERTER_REGISTRY.convert(Long.class,primaryId);
        //根据goodsId 查找商品的价格
        // TODO new一个对象假装是查出来的
        Goods goods = Goods.builder()
                .goodsId(1L)
                .goodsName("iPhone12 Pro Max-1TB")
                .goodsPrice(BigDecimal.valueOf(0.01))
                .build();
        BigDecimal money = goods.getGoodsPrice();
        //TODO 获取用户信息
//        LoginAccount loginAccount = tokenService.getLoginUser(request);
//        ApiAccount account = loginAccount.getAccount();
        // TODO 插入订单记录
        // TODO 记录用户的购买记录
        // TODO 调用统一生成订单接口
        WxPayUnifiedOrderRequest orderRequest = new WxPayUnifiedOrderRequest();
        orderRequest.setSignType(WxPayConstants.SignType.MD5);
        // 订单信息主体
        orderRequest.setBody("购买iPhone12 Pro Max-1TB");
        //TODO 自己生成order_No
//        orderRequest.setOutTradeNo(generateOrderSerialNumber(account.getAccountId()));
        orderRequest.setOutTradeNo(generateOrderSerialNumber(1L));
        orderRequest.setTradeType(WxPayConstants.TradeType.JSAPI);
        // 微信支付价格单位：分
        orderRequest.setTotalFee(BaseWxPayRequest.yuanToFen(CONVERTER_REGISTRY.convert(String.class, money)));
        // 获取微信支付用户的openId
        orderRequest.setOpenid(wxMaService.getUserService().getSessionInfo(code).getOpenid());
        //TODO 支付用户终端IP
//        orderRequest.setSpbillCreateIp(loginAccount.getIpaddr());
        orderRequest.setSpbillCreateIp("192.168.3.195");
        Date now = DateUtil.date();
        Date afterDate = DateUtil.offset(now, DateField.MINUTE, 10);//10分钟后
        orderRequest.setTimeStart(DateUtil.format(now, "yyyyMMddHHmmss"));
        orderRequest.setTimeExpire(DateUtil.format(afterDate, "yyyyMMddHHmmss"));
        orderRequest.setNotifyUrl(notifyUrl + "/api/weChatPay/notifyWxPay");
        Object order = wxPayService.createOrder(orderRequest);
        return ApiResult.ok(order);
    }


    /**
     * 微信支付-app拉起支付
     *
     * @param request
     * @return
     * @throws WxPayException
     * @throws WxErrorException
     */
    @RequestMapping(value = "/toPayByWeChat", method = RequestMethod.POST)
    @Transactional(rollbackFor = Exception.class)
    @PassToken
    public ApiResult toPayByWeChat(HttpServletRequest request) throws WxPayException {
//        String primaryId = map.get("goodsId");
//        log.info("参数的productId：{{}}", primaryId);
//        if (StringUtils.isAnyBlank(primaryId)) {
//            return ApiResult.fail("参数不能为null");
//        }
//        Long goodsId = CONVERTER_REGISTRY.convert(Long.class,primaryId);
        //根据goodsId 查找商品的价格
        // TODO new一个对象假装是查出来的
        Goods goods = Goods.builder()
                .goodsId(1L)
                .goodsName("iPhone12 Pro Max-1TB")
                .goodsPrice(BigDecimal.valueOf(0.01))
                .build();
        BigDecimal money = goods.getGoodsPrice();
        //TODO 获取用户信息
//        LoginAccount loginAccount = tokenService.getLoginUser(request);
//        ApiAccount account = loginAccount.getAccount();
        // TODO 插入订单记录
        // TODO 记录用户的购买记录
        // TODO 调用统一生成订单接口
        WxPayUnifiedOrderRequest orderRequest = new WxPayUnifiedOrderRequest();
        orderRequest.setAppid(weChatPayAppId);
        orderRequest.setSignType(WxPayConstants.SignType.MD5);
        // 订单信息主体
        orderRequest.setBody("购买iPhone12 Pro Max-1TB");
        //TODO 自己生成order_No
//        orderRequest.setOutTradeNo(generateOrderSerialNumber(account.getAccountId()));
        orderRequest.setOutTradeNo(generateOrderSerialNumber(1L));
        orderRequest.setTradeType(WxPayConstants.TradeType.APP);
        // 微信支付价格单位：分
        orderRequest.setTotalFee(BaseWxPayRequest.yuanToFen(CONVERTER_REGISTRY.convert(String.class, money)));
        //TODO 支付用户终端IP
//        orderRequest.setSpbillCreateIp(loginAccount.getIpaddr());
        orderRequest.setSpbillCreateIp("192.168.3.195");
        Date now = DateUtil.date();
        Date afterDate = DateUtil.offset(now, DateField.MINUTE, 10);//10分钟后
        orderRequest.setTimeStart(DateUtil.format(now, "yyyyMMddHHmmss"));
        orderRequest.setTimeExpire(DateUtil.format(afterDate, "yyyyMMddHHmmss"));
        orderRequest.setNotifyUrl(notifyUrl + "/api/weChatPay/notifyWxPay");
        Object order = wxPayService.createOrder(orderRequest);
        return ApiResult.ok(order);
    }

    /**
     * Create By Renbowen
     *
     * @Date: 2020/10/11 14:29
     * @Description: 微信支付回调
     */
    @RequestMapping(value = "/notifyWxPay")
    @PassToken
    public String notifyMiniProgramPay(HttpServletRequest request, HttpServletResponse response) {
        try {
            String xmlResult = IOUtils.toString(request.getInputStream(), request.getCharacterEncoding());
            WxPayOrderNotifyResult notifyResult = wxPayService.parseOrderNotifyResult(xmlResult);
            // 结果正确 outTradeNo
            String orderSn = notifyResult.getOutTradeNo();
            String tradeNo = notifyResult.getTransactionId();
            String totalFee = BaseWxPayResult.fenToYuan(notifyResult.getTotalFee());
            if ("SUCCESS".equals(notifyResult.getResultCode())) {
                //TODO 支付成功->执行操作
                System.out.println("商户生成的订单流水号：" + orderSn);
                System.out.println("微信支付流水号：" + tradeNo);
                System.out.println("支付金额/元：" + totalFee);
                System.out.println("支付成功->执行操作");
            }
            //自己处理订单的业务逻辑，需要判断订单是否已经支付过，否则可能会重复调用
            return WxPayNotifyResponse.success("成功");
        } catch (Exception e) {
            log.error("微信回调结果异常,异常原因{{}}", e.getMessage());
//            WxPayNotifyResponse.fail(e.getMessage());
            return WxPayNotifyResponse.success("code:" + 9999 + "微信回调结果异常,异常原因:" + e.getMessage());
        }
    }


    /**
     * 微信退款
     *
     * @return
     * @throws WxPayException
     */
    @RequestMapping(value = "/refundByWxPay", method = RequestMethod.POST)
    @PassToken
    public ApiResult refundByMiniProgram() throws WxPayException {
        try {
            //TODO 根据订单id查询订单信息，然后执行退款参数封装
            // 详细参数请下载源码自行查看补充 类：WxPayRefundRequest
            WxPayRefundRequest refundRequest = new WxPayRefundRequest();
            refundRequest.setTransactionId("4200000758202010118395183204");
            refundRequest.setOutTradeNo("202010111740111263");
            refundRequest.setOutRefundNo(generateOrderSerialNumber(1L) + "-refund");
            refundRequest.setTotalFee(BaseWxPayRequest.yuanToFen("0.01"));
            refundRequest.setRefundFee(BaseWxPayRequest.yuanToFen("0.01"));
            WxPayRefundResult wxPayRefundResult = wxPayService.refund(refundRequest);
            if ("SUCCESS".equals(wxPayRefundResult.getResultCode())) {
                //TODO 支付成功->执行操作
                System.out.println("商户生成的支付时的订单流水号：" + wxPayRefundResult.getOutTradeNo());
                System.out.println("微信支付时的流水号：" + wxPayRefundResult.getTransactionId());
                System.out.println("商户生成的微信退款流水号：" + wxPayRefundResult.getOutRefundNo());
                System.out.println("退款金额/元：" + BaseWxPayResult.fenToYuan(wxPayRefundResult.getRefundFee()));
                System.out.println("退款成功->执行操作");
            }
            return ApiResult.ok("退款成功");
        } catch (Exception e) {
            log.error("微信退款结果异常,异常原因{{}}", e.getMessage());
            return ApiResult.fail(e.getMessage());
        }

    }
}

/**
 * 商品实体
 */
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
class Goods {

    // 商品id
    private Long goodsId;

    // 商品名字
    private String goodsName;

    // 商品价格
    private BigDecimal goodsPrice;

    // 省略一系列参数
}

